#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "tokens.h"
#include "keywords.c"
#include "lexer.h"

FILE * tape;//arquivo de entrada.

void
skipspaces(void)
{
    int head;
    while(isspace(head = getc(tape)));
    ungetc(head, tape);
    if((head = getc(tape)) == '{'){
	while ((head = getc(tape)) != '}');
	skipspaces();
    }else{
	ungetc(head, tape);
    }
}

/*
 *ID -> alpha (alphaint)*
 */
isID(void)
{
    int             i = 0;
    lexeme[i] = getc(tape);
    if (isalpha(lexeme[i])) {
        while (isalnum(lexeme[++i] = getc(tape)));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        if (i = iskeyword(lexeme))
            return i;
        return ID;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

char lexeme[MAXLEN]; //vetor para guardar o lexema

int i; //posição do lexema, semelhante a uma cabeça de uma fita

/* NUM -> floating | UINT
 * 
 * floating = UINT ('.' digit* enotation? | enotation) | '.' digit+ enotation?
 *
 * enotation = 'E' ('+'|'-')? digit+
 * 
 * UINT -> ('1'-'9')digit | '0'
 */
isenotation(void)
{
    lexeme[i] = getc(tape);
    if (lexeme[i] == 'E' || lexeme[i] == 'e') {
        lexeme[++i] = getc(tape);
        if (lexeme[i] == '+' || lexeme[i] == '-'){
            lexeme[++i] = getc(tape);
	}
        if (isdigit(lexeme[i])) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
        }
    }
    ungetc(lexeme[i], tape);
    lexeme[i] = 0;
    return 0;
}

isUINT(void)
{
    i = 0;
    lexeme[i] = getc(tape);
    if (isdigit(lexeme[i])) {
        if (lexeme[i] == '0') {
            lexeme[1] = 0;
            return UINT;
        }
        while (isdigit(lexeme[++i] = getc(tape)));
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
        return UINT;
    }
    ungetc(lexeme[i], tape);
    return 0;
}

isNUM(void)
{
    int lenght;
    if (isUINT()) {
        if ((lexeme[i] = getc(tape)) == '.') {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i], tape);
        lexeme[i] = 0;
	lenght = isenotation();
        if (lenght>0)
            return FLOAT;
        return UINT;
    }
    if ((lexeme[i] = getc(tape)) == '.') {
        if (isdigit(lexeme[++i] = getc(tape))) {
            while (isdigit(lexeme[++i] = getc(tape)));
            ungetc(lexeme[i], tape);
            lexeme[i] = 0;
            isenotation();
            return FLOAT;
        }
        ungetc(lexeme[i--], tape);
        ungetc('.', tape);
        return 0;
    }
    ungetc(lexeme[i], tape);
    return 0;
}


/*
 * GEQ -> '>''='
 */
isGEQ(void)
{
  int i = 0;
  if((lexeme[i++] = getc(tape)) == '>'){
     if((lexeme[i++] = getc(tape)) == '='){
        lexeme[i] = 0;
        return GEQ;
     }
     ungetc(lexeme[--i], tape);
     lexeme[i] = 0;
     return lexeme[0];
  }
  ungetc(lexeme[--i], tape);
  return 0;

}

/*
 * LEQ -> '<''='
 *
 * NEQ -> '<''>'
 */
isLEQ(void)
{
  int i = 0;
  if((lexeme[i++] = getc(tape)) == '<'){
     if((lexeme[i++] = getc(tape)) == '='){
        lexeme[i] = 0;
        return LEQ;
     }else if(lexeme[i-1] == '>'){
	lexeme[i] = 0;
	return NEQ;
     }
     ungetc(lexeme[--i], tape);
     lexeme[i] = 0;
     return lexeme[0];
  }
  ungetc(lexeme[--i], tape);
  return 0;
}

/*
 * ASSGNMT -> ':''='
 */
isASSGNMT(void)
{
  int i = 0;
  if((lexeme[i++]=getc(tape))==':'){
    if((lexeme[i++]=getc(tape))=='='){
      lexeme[i] = 0;
      return ASSGNMT;
    }
    ungetc(lexeme[--i],tape);
    lexeme[i]=0;
    return lexeme[0];
  }
  ungetc(lexeme[--i],tape);
  return 0;
}

//verificação do token correspondente
gettoken(void)
{
    int token;
    skipspaces();
    if (token = isID())
        return token;
    if (token = isNUM())
        return token;
    if (token = isGEQ())
	return token;
    if (token = isLEQ())
	return token;
    if (token = isASSGNMT())
	return token;
    lexeme[1] = 0;
    return lexeme[0] = getc(tape);
}

int lookahead; //próximo token a ser analisado

//verificação do token esperado pela gramática da linguagem
void match(int expected)
{
    if (lookahead == expected) {
	lookahead = gettoken();
    } else {
	fprintf(stderr, "token mismatch: found %d but %d expected\n", lookahead, expected);
	exit(-1);
    }
}